use std::{collections::HashMap, fs, path::Path, sync::Arc};

use crate::error::{Error, Result};
use arc_swap::ArcSwapOption;
use charming::Chart;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use shq_common::prelude::{
    DataType, Parameter, get_work_path, report::{AuthFilter, ReportGroup, SeriesSource, SpecialRows, TimeType, Unit}
};
mod big_table;
pub mod column;
mod data_source;
mod drill_down;
pub use big_table::*;
pub use column::*;
pub use data_source::*;
pub use drill_down::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Report {
    //报表类型
    pub r#type: ReptType,
    //标题
    pub title: String,
    //确定每条记录唯一性的健
    pub unique_columns: Vec<String>,
    //默认排序
    pub default_order: Option<String>,
    //单位
    #[serde(default)]
    pub unit: Unit,
    //显示限制 用于chart报表
    #[serde(default)]
    pub show_limit: Option<u32>,
    //图表序列的数据源 用于chart报表
    #[serde(default)]
    pub series_source: Option<SeriesSource>,
    //过滤权限
    #[serde(default)]
    pub auth_filter: Option<AuthFilter>,
    //列
    pub columns: Vec<column::Column>,
    //行上的列(用于cross报表)
    #[serde(default)]
    pub rows: Vec<column::Column>,
    //数据单元格上的列(用于cross报表)
    #[serde(default)]
    pub cells: Vec<column::Column>,
    //列上的层次定义(用于cross报表)
    #[serde(default)]
    pub column_levels: Vec<ColumnLevel>,
    //参数
    pub params: Vec<Parameter>,
    //数据源
    pub data_source: data_source::DataSource,
    //数据钻取
    #[serde(default)]
    pub drill_downs: Vec<drill_down::DrillDown>,
    //分组
    #[serde(default)]
    pub groups: Vec<ReportGroup>,
    #[serde(default)]
    pub export_sheet_col_name: Option<String>,
    //图表
    #[serde(default)]
    pub chart: Option<Chart>,
    //特殊行
    #[serde(default)]
    pub special_rows: Option<SpecialRows>,
}
impl Report {
    pub(crate) fn get_leaf_columns(&self) -> Vec<&column::Column> {
        let mut leaf_columns = vec![];
        for c in self.columns.iter() {
            let mut ccols = c.get_leaf_columns();
            leaf_columns.append(&mut ccols);
        }
        for c in self.rows.iter() {
            let mut ccols = c.get_leaf_columns();
            leaf_columns.append(&mut ccols);
        }
        for c in self.cells.iter() {
            let mut ccols = c.get_leaf_columns();
            leaf_columns.append(&mut ccols);
        }
        leaf_columns
    }
    pub fn col_is_front_must(&self, col_name: &str) -> bool {
        self.columns
            .iter()
            .find(|c| c.name.as_deref() == Some(col_name))
            .map_or(false, |c| c.front_must)
    }
    pub async fn parse(&mut self, rept_name: &str) -> anyhow::Result<()> {
        if self.r#type == ReptType::Chart {
            if self.chart.is_none() {
                anyhow::bail!("报表类型为Chart时，chart不能为空");
            }
            for col in self.columns.iter() {
                if col.children.len() > 0 {
                    return Err(anyhow::anyhow!(
                        "报表类型为Chart时，columns下的列不能有子列"
                    ));
                }
            }
        } else {
            if self.chart.is_some() {
                anyhow::bail!("报表类型不为Chart时，chart不用定义");
            }
        }
        if self.r#type == ReptType::Cross {
            if self.rows.len() == 0 {
                anyhow::bail!("报表类型为Cross时，rows不能为空");
            }
            if self.cells.len() == 0 {
                anyhow::bail!("报表类型为Cross时，cells不能为空");
            }
            if self.column_levels.len() == 0 {
                anyhow::bail!("报表类型为Cross时，column_levels不能为空");
            }
            for r in self.rows.iter() {
                if r.children.len() > 0 {
                    return Err(anyhow::anyhow!("报表类型为Cross时，rows下的列不能有子列"));
                }
            }
            for c in self.cells.iter() {
                if c.children.len() > 0 {
                    return Err(anyhow::anyhow!("报表类型为Cross时，cells下的列不能有子列"));
                }
            }
            for c in self.columns.iter() {
                if c.children.len() > 0 {
                    return Err(anyhow::anyhow!(
                        "报表类型为Cross时，columns下的列不能有子列"
                    ));
                }
            }
            if self.data_source.source_type == DataSourceType::Func
                || self.data_source.source_type == DataSourceType::SqlFile
            {
                anyhow::bail!("报表类型为Cross时，数据源类型只能是Talbe或者Sql");
            }
            for cl in self.column_levels.iter() {
                if self
                    .columns
                    .iter()
                    .find(|c| c.name.as_deref() == Some(cl.id_col.as_str()))
                    .is_none()
                {
                    return Err(anyhow::anyhow!(
                        "column_levels-id_col:{}在columns中不存在",
                        cl.id_col
                    ));
                }
                if self
                    .columns
                    .iter()
                    .find(|c| c.name.as_deref() == Some(cl.name_col.as_str()))
                    .is_none()
                {
                    return Err(anyhow::anyhow!(
                        "column_levels-name_col:{}在columns中不存在",
                        cl.name_col
                    ));
                }
                if let Some(oc) = &cl.order_col {
                    if self
                        .columns
                        .iter()
                        .find(|c| c.name.as_deref() == Some(oc.as_str()))
                        .is_none()
                    {
                        return Err(anyhow::anyhow!(
                            "column_levels-order_col:{}在columns中不存在",
                            oc
                        ));
                    }
                }
            }
            for rg in self.groups.iter() {
                if self
                    .rows
                    .iter()
                    .find(|c| c.name.as_deref() == Some(rg.by.as_str()))
                    .is_none()
                {
                    return Err(anyhow::anyhow!("groups-by:{}在rows中不存在", rg.by));
                }
                for nc in rg.name_cols.iter() {
                    if self
                        .rows
                        .iter()
                        .find(|c| c.name.as_deref() == Some(nc.as_str()))
                        .is_none()
                    {
                        return Err(anyhow::anyhow!("groups-name_cols:{}在rows中不存在", nc));
                    }
                }
            }
        } else {
            if self.rows.len() > 0 {
                anyhow::bail!("报表类型不为Cross时，rows不用定义");
            }
            if self.cells.len() > 0 {
                anyhow::bail!("报表类型不为Cross时，cells不用定义");
            }
            if self.column_levels.len() > 0 {
                anyhow::bail!("报表类型不为Chart时，column_levels不用定义");
            }
        }
        let leafs = self.get_leaf_columns();
        if self.unique_columns.len() == 0 {
            anyhow::bail!("unique_columns不能为空");
        }
        for uc in self.unique_columns.iter() {
            if leafs
                .iter()
                .find(|c| c.name.as_deref() == Some(uc.as_str()))
                .is_none()
            {
                anyhow::bail!("unique_columns:{}在columns中不存在", uc);
            }
        }
        if let Some(af) = &self.auth_filter {
            if leafs
                .iter()
                .find(|c| c.name.as_deref() == Some(af.col_name.as_str()))
                .is_none()
            {
                anyhow::bail!("auth_filter-col_name:{}在columns中不存在", af.col_name);
            }
        } else {
            let key_cols = &["EMID", "DPID", "PDID", "EMNO", "EMNM", "DPNM", "PDNM"];
            let mut count = 0_u8;
            for k in key_cols.iter() {
                if leafs.iter().any(|c| c.name.as_deref() == Some(*k)) {
                    count += 1;
                }
            }
            if count >= 2 {
                log::warn!("column中含有员工，部门字段，但没有配置auth_filter");
            }
        }
        let has_avg = leafs.iter().any(|l| l.group_calc == GroupCalc::Avg);
        let has_acbl = leafs.iter().any(|l| l.group_calc == GroupCalc::Acbl);
        let count = self
            .params
            .iter()
            .filter(|p| p.data_type == DataType::Date)
            .count();
        if has_avg && count < 2 {
            anyhow::bail!("columns中存在平均值的计算，参数中必须有开始日期和截止日期,且必须在其它日期参数的前面");
        }
        if has_acbl && count == 0 {
            anyhow::bail!("columns中存在Acbl的计算，参数中必须有日期参数");
        }
        if self.groups.len() > 0 {
            if self.r#type != ReptType::Cross
                && leafs.iter().all(|l| {
                    !l.col_exp
                        .as_ref()
                        .map(|e| e.contains("(") && e.contains(")"))
                        .unwrap_or_default()
                        && l.group_calc == GroupCalc::Any
                })
            {
                log::warn!("报表配置了groups，但columns中没有配置group_calc");
            }
        }
        for g in self.groups.iter() {
            if g.by.is_empty() {
                return Err(anyhow::anyhow!("groups-by不能为空"));
            }
            if g.name_cols.is_empty() {
                return Err(anyhow::anyhow!("groups-name_cols不能为空"));
            }
            if leafs
                .iter()
                .find(|c| c.name.as_deref() == Some(g.by.as_str()))
                .is_none()
            {
                return Err(anyhow::anyhow!("groups-by:{}在columns中不存在", g.by));
            }
            for nc in g.name_cols.iter() {
                if leafs
                    .iter()
                    .find(|c| c.name.as_deref() == Some(nc.as_str()))
                    .is_none()
                {
                    return Err(anyhow::anyhow!("groups-name_cols:{}在columns中不存在", nc));
                }
            }
        }
        if let Some(ss)=self.series_source.as_ref(){
            let pds=ss.forecast_period.unwrap_or(0);
            if pds>0 && ss.time_type==TimeType::None{
                return Err(anyhow::anyhow!("series_source-forecast_period:配置为{}，时间类型不能为None", pds));
            }
        }
        let col_types = self.data_source.parse(rept_name, &self).await?;
        let unique_cols: Vec<&str> = self.unique_columns.iter().map(|uc| uc.as_str()).collect();
        set_leaf_columns_props(
            &mut self.columns,
            &unique_cols,
            &col_types,
            self.unit.clone(),
        )?;
        Ok(())
    }
    pub(crate) async fn get_default_param_vals(&self) -> anyhow::Result<Vec<(&str, String)>> {
        let mut params: Vec<(&str, String)> = Vec::new();
        for p in self.params.iter() {
            let val = p.default_value.get_value().await?;
            params.push((p.name.as_str(), val));
        }
        Ok(params)
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum ReptType {
    List,
    Chart,
    Cross,
}
impl Default for ReptType {
    fn default() -> Self {
        ReptType::List
    }
}
impl<'de> Deserialize<'de> for ReptType {
    fn deserialize<D>(deserializer: D) -> std::result::Result<ReptType, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "list" => Ok(ReptType::List),
            "chart" => Ok(ReptType::Chart),
            "cross" => Ok(ReptType::Cross),
            _ => Err(serde::de::Error::custom(format!("未知的ReptType:{s}"))),
        }
    }
}

static REPT_CONFS: Lazy<ArcSwapOption<HashMap<String, &'static Report>>> =
    Lazy::new(|| ArcSwapOption::const_empty());
pub async fn init_rept_config() -> Result<()> {
    let conf_path = format!("{}/rept_confs", get_work_path());
    let mut conf_map: HashMap<String, &'static Report> = HashMap::new();
    init_big_table().await?;
    for entry in fs::read_dir(conf_path)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            continue;
        } else {
            let file_name = path.file_name().unwrap().to_str().unwrap();
            if !file_name.ends_with(".yaml") {
                continue;
            }
            let conf_str = fs::read_to_string(&path)?;
            let conf: Report = serde_yaml::from_str(&conf_str)
                .or_else(|err| Err(Error::from_conf(file_name, format!("yaml解析失败:{err}"))))?;
            let conf_ref = Box::leak(Box::new(conf));
            let file_name = &file_name[0..file_name.len() - 5];
            let res = conf_ref
                .parse(file_name)
                .await
                .or_else(|err| Err(Error::from_conf(file_name, format!("验证失败:{err}"))));
            if let Err(err) = res {
                log::error!("{}:{}", file_name, err);
            }
            conf_map.insert(file_name.to_string(), conf_ref);
        }
    }
    for (k, v) in conf_map.iter() {
        let col_names = v
            .get_leaf_columns()
            .iter()
            .map(|c| c.name.as_deref().unwrap())
            .collect::<Vec<_>>();
        let params: Vec<&str> = v.params.iter().map(|p| p.name.as_str()).collect();
        for dd in v.drill_downs.iter() {
            dd.parse(&col_names, &params, Some(&conf_map))
                .await
                .or_else(|err| Err(Error::from_conf(k, err.to_string())))?;
        }
    }
    REPT_CONFS.store(Some(Arc::new(conf_map)));
    Ok(())
}
pub async fn reload_rept_config(path: &Path) -> Result<()> {
    let file_name = path.file_name().unwrap().to_str().unwrap();
    if !file_name.ends_with(".yaml") {
        return Ok(());
    }
    let rept_name = &file_name[0..file_name.len() - 5];
    let conf_str = fs::read_to_string(path)?;
    let mut conf: Report = serde_yaml::from_str(&conf_str)
        .or_else(|err| Err(Error::from_conf(file_name, format!("yaml解析失败:{err}"))))?;
    conf.parse(rept_name)
        .await
        .or_else(|err| Err(Error::from_conf(rept_name, format!("验证失败:{err}"))))?;
    let col_names = conf
        .get_leaf_columns()
        .iter()
        .map(|c| c.name.as_deref().unwrap())
        .collect::<Vec<_>>();
    let params: Vec<&str> = conf.params.iter().map(|p| p.name.as_str()).collect();
    for dd in conf.drill_downs.iter() {
        dd.parse(&col_names, &params, None)
            .await
            .or_else(|err| Err(Error::from_conf(rept_name, err.to_string())))?;
    }
    let conf_ref = Box::leak(Box::new(conf));
    let conf_map = REPT_CONFS.load().clone().unwrap();
    let mut conf_map2: HashMap<String, &'static Report> = HashMap::new();
    for (k, v) in conf_map.iter() {
        if k == rept_name {
            conf_map2.insert(k.clone(), conf_ref);
        } else {
            conf_map2.insert(k.clone(), *v);
        }
    }
    REPT_CONFS.store(Some(Arc::new(conf_map2)));
    Ok(())
}
pub fn get_rept_config(rept_name: &str) -> Option<&'static Report> {
    let conf_map = REPT_CONFS.load().clone().unwrap();
    conf_map.get(rept_name).copied()
}
//列上的层次定义(用于cross报表)
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ColumnLevel {
    //id列的名称
    pub id_col: String,
    //name列的名称
    pub name_col: String,
    //排序列的名称
    pub order_col: Option<String>,
    //小计计算规则
    #[serde(default)]
    pub sub_total_calc: Option<GroupCalc>,
}

pub(crate) fn get_group_by<'a>(
    groups: &'a [ReportGroup],
    rows: Option<&'a [Column]>,
) -> Vec<&'a str> {
    let mut group_by: Vec<&str> = Vec::new();
    let glen = groups.len();
    if glen > 0 {
        for g in groups.iter(){
            group_by.push(g.by.as_str());
        }
    } else {
        let llen = rows.map(|r| r.len()).unwrap_or(0);
        if llen > 0 {
            let cols: Vec<&Column> = rows.iter()
                .flat_map(|r| {
                    r.iter().filter(|c| {
                        c.name.is_some()
                            && c.display == false
                            && c.children.len() == 0
                            && c.title.is_none()
                    })
                }).collect();
            for c in cols {
                group_by.push(c.name.as_deref().unwrap());
            }
        }
    }
    group_by
}

pub(crate) fn set_leaf_columns_props(
    columns: &mut Vec<Column>,
    unique_cols: &[&str],
    col_types: &Vec<(String, DataType)>,
    unit: Unit,
) -> anyhow::Result<()> {
    for c in columns.iter_mut() {
        if c.children.len() > 0 {
            for cc in c.children.iter_mut() {
                cc.set_leaf_columns_type(col_types, unit)?;
            }
        } else {
            c.set_leaf_columns_type(col_types, unit)?;
            let is_uniq = unique_cols.iter().any(|uc| Some(*uc) == c.name.as_deref());
            if is_uniq && c.display == false {
                c.unit = Some(Unit::Yuan);
                c.front_must = true;
            }
        }
    }
    Ok(())
}


